<!-- 当前正在咨询页面 -->
<template>
	<view>
		<!-- 顶部提示区域 -->
		<u-sticky class="top-tip sticky" style="background-color: #FFFFFF;">
			<view class="top-tip" style="background-color: #AFAFAF;">
				咨询时间仅剩
				<u-count-down ref="myCountDown" :timestamp="time" :autoplay="false" :show-hours="isHours" @change="timeChange" separator-color="#FFFFFF" bg-color="#AFAFAF" color="#FFFFFF"></u-count-down>
				秒
			</view>
		</u-sticky>
		<!-- 聊天窗口主体内容区域 -->
		<scroll-view class="chat-container" :scroll-top="scrollTop" :style="{ height: minHeight + 'px' }" :show-scrollbar="false" :scroll-y="true" @scrolltoupper="scrollUpTop">
			<view class="scroll-views" id="message-scroll">
				<view class="scroll-to-top-tip" v-if="chatDataList && isScrollTopTipShow">没有更多了</view>
				<block v-for="(chat, index) in chatDataList" :key="index">
					<!-- 每个 chatting-item 即一个消息项 -->
					<chatting-item :message="chat" @messageImageClick="messageImageClick"></chatting-item>
				</block>
			</view>
		</scroll-view>
		<!-- 底部输入和发送区域 -->
		<form class="chat-form">
			<view class="uni-form-item uni-column chat-input-box">
				<u-input v-model="inputValue" :clearable="false" :custom-style="{ width: '450rpx' }" placeholder="在此输入内容" />
				<view class="img-box" @click.stop="uploadImage"><u-icon name="photo" size="50" color="#999999"></u-icon></view>
				<button class="submitBtn" form-type="submit" type="error" @click="submitClick">发送</button>
			</view>
		</form>

		<!-- 模态框,用于咨询时间结束后的提示 -->
		<u-modal v-model="tipShow" :content="content" :show-cancel-button="true" @confirm="outChatting"></u-modal>
	</view>
</template>

<script>
import TIM from 'tim-wx-sdk'; // 微信小程序环境请取消本行注释，并注释掉 import TIM from 'tim-js-sdk';
import TIMUploadPlugin from 'tim-upload-plugin'; // 使用前请将 IM SDK 升级到v2.9.2或更高版本
// 创建 SDK 实例，TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
let options = {
	SDKAppID: 1400622577 // 接入时需要将0替换为您的即时通信应用的 SDKAppID
};
let tim = TIM.create(options); // SDK 实例通常用 tim 表示
// 注册腾讯云即时通信IM上传插件
tim.registerPlugin({
	'tim-upload-plugin': TIMUploadPlugin
});

export default {
	data() {
		return {
			// 聊天区域的最小高度
			minHeight: 0,
			// 消息数据列表
			chatDataList: [],
			form: {
				value: ''
			},
			// 是否显示 小时 的部分，默认false不显示
			isHours: false,
			// 当前咨询剩余时间
			time: 0,
			// 倒计时结束后显示模态框提示
			tipShow: false,
			content: '咨询时间结束，立即退出会话？',
			// 输入框中的 value 值
			inputValue: '',
			scrollTop: 0,

			// 接收消息的用户的ID
			toMessageUserID: '',
			// 上一条消息记录的时间(此时间主要用于判断是否需要渲染时间节点)
			lastMessageTime: 0,
			// 此字段决定如果两条消息之间的时间差 maxTime 秒，则会在消息间渲染出后一条时间的时间节点
			maxTime: 120,

			// 拉取历史消息 用于分页续拉的消息 ID 第一次拉取时不需要
			nextReqMessageID: '',
			// 对 scroll-view 触顶事件做防抖节流
			isGetMessageList: false,
			// 当前消息区域的高度
			messageViewHeight: 0,
			// 控制是否显示消息顶部的 “没有更多了” 的提示文字
			isScrollTopTipShow: false,
			isLoading: false,	// 发送消息的防抖节流
		};
	},
	// 在此接收消息页传递过来的参数即被点击会话项的 id
	async onLoad(options) {
		// options 是页面传递过来的参数
		// console.log(options);
		this.toMessageUserID = options.userID
		console.log('toMessageUserID', this.toMessageUserID);
		this.checkTalkConsult()		// 获取当前用户的时间以及状态信息
		// 动态设置页面标题
		uni.setNavigationBarTitle({
			title: options.user_name
		})
		// 如果页面没有任何消息数据则尝试拉取历史消息
		if (!this.chatDataList.lengt) {
			// 拉取历史消息
			await this.getMessageList();
		}
		// 设置消息为已读
		tim.setMessageRead({ conversationID: 'C2C' + this.toMessageUserID });

		if (this.time < 3600) {
			this.isHours = false;
			if (this.time === 0) {
				this.isSubmit = true;
			}
		}

		this.$nextTick(() => {
			//进入页面滚动到底部
			this.scrollTop = 9999;
		});
		
	},
	async created() {
		this.$u.utils.login();
		// 获取设备屏幕高度
		const h = await uni.getSystemInfoSync();
		this.minHeight = h.windowHeight - 107; // 减去上 47px 和下 58px
		// this.scrollTop = this.minHeight;
		// console.log('当前设备屏幕高度' + this.minHeight);
	}, // 监听页面返回事件
	onBackPress(options) {
		// 设置消息为已读
		tim.setMessageRead({ conversationID: 'C2C' + this.toMessageUserID });
	},
	onHide() {
		// 设置消息为已读
		tim.setMessageRead({ conversationID: 'C2C' + this.toMessageUserID });
	},
	watch: {
		time(time) {
			if (time > 3600) {
				this.isHours = true; 	// 把不显示小时的功能关闭
			}
		},
		// 监听页面消息数据列表
		chatDataList(list) {
			this.messageImageList = [];
			list.forEach(message => {
				if (!message.image) return;
				// 拿到所有图片的链接地址
				this.messageImageList.push(message.image);
			});
			// console.log(this.messageImageList);
		}
	},
	mounted() {
		// 监听收到推送的单聊、群聊、群提示、群系统通知的新消息
		tim.on(TIM.EVENT.MESSAGE_RECEIVED, this.$onMessageReceived, this);
	},
	// 在此解除相关的事件绑定
	destroyed() {
		// 一定要解除相关的事件绑定
		tim.off(TIM.EVENT.MESSAGE_RECEIVED, this.$onMessageReceived);
	},
	methods: {
		// 获取用户的时间以及状态是数据
		async checkTalkConsult() {
			const res = await this.$u.api.checkTalkConsult({user_id: this.toMessageUserID})
			if(!res) return
			// console.log('时间和状态数据', res);
			this.time = res.left_time
			// res.on_line 为true 则用户正在当前律师的聊天窗口则开启倒计时否则暂停倒计时
			if(res.on_line) return this.$refs.myCountDown.start()
			this.$u.toast('当前用户已退出聊天窗口')
			setTimeout(() => {
				// console.log('暂停了倒计时');
				this.$refs.myCountDown.end()	// 否则暂停倒计时
			}, 500)
		},
		// 拉取历史消息
		async getMessageList() {
			// 存放此次拉取到的消息数据
			let messageList = [];
			// 获取历史消息
			const res = await tim.getMessageList({
				conversationID: `C2C${this.toMessageUserID}`,
				// conversationID: 'C2C001',
				nextReqMessageID: this.nextReqMessageID, // 用于分页续拉的消息 ID，第一次拉取时不需要
				count: 15 // 默认和最值均为 15 条
			});
			// console.log(this.nextReqMessageID);
			// console.log(res);
			// 判断消息列表是否有历史消息
			if (res.data.messageList.length < 1) return (this.isScrollTopTipShow = true);
			console.log('拉取到的历史消息', res.data.messageList);
			// 有历史消息的情况
			// 遍历消息列表处理每一条消息
			res.data.messageList.forEach(message => {
				// 消息存入消息队列时的数据格式对象
				const statusData = {
					isShow: false, // false 为我方消息
					src: this.vuex_user.avatarUrl, // 头像路径
					text: '',
					image: '', // 图片消息时，此字段不为空
					insertTime: '' // 如果两条消息的时间差较长则次字段会被赋值
				};
				// 判断该条消息发送者是否为 对方
				if (message.from === this.toMessageUserID) {
					statusData.isShow = true; // true 为对方消息
					statusData.src = message.avatar; 		// 对方的头像路径
				}
				// 判断消息是文字还是图片
				if (message.type === 'TIMTextElem') {
					statusData.text = message.payload.text;
				} else if (message.type === 'TIMImageElem') {
					// 把接收到的图片的 url 取出来
					statusData.image = message.payload.imageInfoArray[0].url;
				}
				// 判断是否需要渲染发送消息的时间
				if (this.isInsertThisMessage(message.time)) {
					statusData.insertTime = this.$u.utils.formatDate(this.lastMessageTime);
				}

				// 最后把处理完的这条消息添加到页面消息队列中，注意数据的存放顺序
				// this.chatDataList.unshift(statusData)
				messageList.push(statusData);
			});
			// 把此次获取消息时得到的 续拉消息ID 存储起来以备后续使用
			this.nextReqMessageID = res.data.nextReqMessageID;

			// 把获取到的历史消息放到页面已有消息队列的前面(前面的才会渲染到上面)
			this.chatDataList = [...messageList, ...this.chatDataList];

			// 这里用延迟才能获取到 scroll-view 重新渲染后最新的高度
			setTimeout(() => {
				// 获取当前最新的 scroll-view 的高度
				const query = uni.createSelectorQuery().in(this);
				let nodesRef = query.select('#message-scroll');
				nodesRef
					.boundingClientRect(res => {
						// console.log(res);
						if (this.messageViewHeight > 0) {
							// console.log('修正了滚动条');
							this.scrollTop = res.height - this.messageViewHeight + res.top;
							// console.log('scrollTop = ', this.scrollTop);
						}
						this.messageViewHeight = res.height;
						// console.log('最新的scroll-view高度', this.messageViewHeight);
					})
					.exec();
			}, 1);
		},
		// 聊天区域触顶事件
		scrollUpTop() {
			// 防抖
			if (this.isGetMessageList) return;
			this.isGetMessageList = true;
			// console.log('触发了触顶事件');
			this.getMessageList();
			// 延迟 1秒 后再打开节流阀
			setTimeout(() => {
				this.isGetMessageList = false;
			}, 1000);
		},
		// 监听顶部时间变化的事件
		timeChange(time) {
			if (time < 3600) {
				this.isHours = false;
			}
			// 时间为 0 则倒计时结束，则显示出模态框提示
			if (time === 0) {
				this.isSubmit = true;
				return (this.tipShow = true);
			}
		},
		// 模态框中的确定按钮点击事件，即退出当前页面
		outChatting() {
			this.$u.route({
				type: 'back'
			});
		},
		// 发送纯文本消息
		async textMessage(value) {
			// 1. 创建消息实例，接口返回的实例可以上屏
			let message = tim.createTextMessage({
				to: this.toMessageUserID, // 'admin1_1'
				conversationType: 'C2C', // 会话类型：单聊类型
				payload: {
					text: value
				}
			});
			// 2. 发送消息
			let res = await tim.sendMessage(message);
			if (res.code !== 0) return false;
			return res.data;
		},
		// 发送按钮点击事件
		async submitClick() {
			// 判断是否发送的消息为空
			if (this.inputValue.length < 1 || this.isLoading) return;
			this.isLoading = true	// 打开节流阀
			// 调用发送消息方法
			const res = await this.textMessage(this.inputValue);
			// console.log(res);
			// res.code 不为 0 则表示发送失败，直接 return 提示发送失败
			if (!res) {
				this.isLoading = false	// 关闭节流阀
				this.$u.toast('发送失败请稍后再试');
				return
			}
			// 将消息存储到页面消息列表中的数据对象格式
			const statusData = {
				isShow: false, // false 为我方消息
				src: this.vuex_user.avatarUrl, // 头像路径
				text: '',
				insertTime: '' // 如果两条消息的时间差较长则次字段会被赋值
			};
			// 判断是否需要渲染发送消息的时间
			if (this.isInsertThisMessage(res.message.time)) {
				statusData.insertTime = this.$u.utils.formatDate(this.lastMessageTime);
			}
			// console.log(this.inputValue);
			// 将输入框中的值放到发送消息对象中
			statusData.text = this.inputValue;
			// 将当前的消息对象 push 到页面消息数组中
			this.chatDataList.push(statusData);

			// 清空输入框
			this.inputValue = '';

			// 调用函数将页面滚动条置底
			this.scrollTOBottom();
			this.scrollTop = 99999 
			this.isLoading = false	// 关闭节流阀
		},
		// 收到的消息
		$onMessageReceived(value) {
			console.log(value);
			// 监听是否收到关于当前用于的特殊状态通知，比如 用户退出当前窗口、用户进入当前窗口、用户充值成功等
			if(value.data[0].from === '_consult_') {
				let data = JSON.parse(value.data[0].cloudCustomData)
				console.log('特殊状态的数据', data);
				switch(data.type) {
					case 'enter':
						if(data.user_im_account === this.toMessageUserID) {
							this.$u.toast('当前用户进入会话')
							// 开启倒计时
							this.time = data.left_time		// 这里是用户进入时返回的时间（单位：秒
							this.$refs.myCountDown.start()
						}
						break;
					case 'out':
						if(data.user_im_account === this.toMessageUserID) {
							this.$u.toast('当前用户已退出会话')
							// 暂停倒计时
							this.$refs.myCountDown.end()
						}
						break;
					case 'exit':	// 意外退出的情况
						if(data.user_im_account === this.toMessageUserID) {
							this.$u.toast('当前用户已退出会话')
							// 暂停倒计时
							this.$refs.myCountDown.end()
						}
						break;
					case 'recharge':	// 当前用户 充值/续费 了时间
						if(data.user_im_account === this.toMessageUserID) {
							this.$u.toast('用户续费了时间')
							// 更新时间
							this.time = data.left_time
							this.$refs.myCountDown.start()		// 开启倒计时
						}
						break;
				}
				return
			}
			// 以下的消息不是属于特殊消息

			// 若需修改消息，需将内存的消息复制一份，不能直接更改消息，防止修复内存消息，导致其他消息监听处发生消息错误
			const event = value;
			event.data.forEach(item => {
				// 判断这条消息是否是当前用户发的
				if (item.conversationID === 'C2C' + this.toMessageUserID) {
					// 将消息存储到页面消息列表中的数据对象格式
					const statusData = {
						isShow: true, // true 为收到的消息
						src: '/static/demoimg/avatar-min.png', // 头像路径
						text: '', // 文本消息时，此字段不为空
						image: '', // 图片消息时，此字段不为空
						insertTime: '' // 如果两条消息的时间差较长则次字段会被赋值
					};
					statusData.src = item.avatar		// 为用户的头像赋值
					// 判断消息是文本还是图片
					if (item.type === 'TIMTextElem') {
						// 文本消息
						// 把接收到的这条消息整合到页面消息数据对象中
						statusData.text = item.payload.text;
					} else if (item.type === 'TIMImageElem') {
						// 把接收到的图片的 url 取出来
						statusData.image = item.payload.imageInfoArray[0].url;
					}
					// 判断是否需要渲染这条消息的时间
					if (this.isInsertThisMessage(item.time)) {
						statusData.insertTime = this.$u.utils.formatDate(this.lastMessageTime);
					}
					// console.log(statusData);
					// 将当前的消息对象 push 到页面消息数组中
					this.chatDataList.push(statusData);
					
					// 设置消息为已读
					tim.setMessageRead({ conversationID: 'C2C' + this.toMessageUserID });
					
					this.scrollTOBottom();
				}
			});

			
		},
		// 发送图片事件
		uploadImage() {
			// album 从相册选图，camera 使用相机
			this.sendImageMessage('album');
		},
		// 发送图片
		async sendImageMessage(type) {
			// 1. 选择图片
			const res = await uni.chooseImage({
				sourceType: [type],
				count: 1
			});
			// console.log(res);
			// 选择了图片则 长度至少为 2
			if (res.length < 2) return; // 长度 < 2 相当于没有选择图片，点击了 “取消” 的场景

			// 2. 创建图片消息实例
			const message = await tim.createImageMessage({
				to: this.toMessageUserID,
				conversationType: 'C2C',
				payload: {
					file: res[res.length - 1]
				},
				onProgress: percent => {
					message.percent = percent;
				}
			});
			console.log('消息实例', message);

			// 3. 发送这条图片消息
			let res2 = await tim.sendMessage(message);
			console.log('发送图片', res2);
			if (res2.code) return this.$u.toast('发送失败请稍后再试');

			// 消息发送成功
			// console.log('图片发送完成');
			// console.log(res2);
			// 将自己的消息渲染到页面上
			const statusData = {
				isShow: false, // false 为我方发送的消息
				src: '', // 头像路径
				text: '', // 文本消息时，此字段不为空
				image: '', // 图片消息时，此字段不为空
				insertTime: '' // 如果两条消息的时间差较长则次字段应该被赋值
			};
			statusData.image = res2.data.message.payload.imageInfoArray[0].url;
			// 判断是否需要渲染这条消息的时间
			if (this.isInsertThisMessage(res2.data.message.time)) {
				statusData.insertTime = this.$u.utils.formatDate(this.lastMessageTime);
			}
			// console.log('图片渲染数据对象', statusData);
			// 将自己的消息渲染到页面上
			this.chatDataList.push(statusData);
			// 调用函数将页面滚动条置底
			this.scrollTOBottom();
			this.scrollTop = 99999
		},

		// 处理是否需要为此条消息插入时间节点的函数(需要传入此条消息的时间戳)
		isInsertThisMessage(time) {
			// 判断这条消息的时间是否比上一条消息超过预定值
			if (time - this.lastMessageTime > this.maxTime) {
				this.lastMessageTime = time;
				return true;
			} else {
				this.lastMessageTime = time;
				return false;
			}
		},
		// 将滚动条置底
		scrollTOBottom() {
			const query = uni.createSelectorQuery().in(this);
			let nodesRef = query.select('#message-scroll');
			nodesRef
				.boundingClientRect(res => {
					this.$nextTick(() => {
						//进入页面滚动到底部
						this.scrollTop = res.height;
					});
				})
				.exec();
		},
		// 消息列表中的图片项的点击事件——图片预览
		messageImageClick(thisImageUrl) {
			uni.previewImage({
				current: thisImageUrl,
				// 当前显示图片的http链接
				urls: this.messageImageList
			});
		}
	}
};
</script>

<style lang="scss" scoped>
.sticky {
	z-index: 99;
}
.uni-app--maxwidth {
	overflow: hidden !important;
}
#status-bottom-view {
	height: 0.1rpx;
	background-color: red;
}
.top-tip {
	height: 95rpx;
	// background: #000000;
	// opacity: 0.3;
	font-family: PingFang SC;
	color: #f5f5f5;
	text-align: center;
	line-height: 95rpx;
	font-size: 32rpx;
}
.chat-container {
	background-color: #f5f5f5;
	margin-bottom: 120rpx;
	padding-bottom: 20rpx;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
}
.scroll-to-top-tip {
	width: 100%;
	text-align: center;
	padding: 10rpx;
	color: #a5b5c1;
	font-size: 24rpx;
}
.chat-form {
	position: fixed;
	bottom: 0;
	left: 0;
	width: 750rpx;
	height: 117rpx;
	box-sizing: border-box;
	padding: 35rpx 14rpx 17rpx 26rpx;
	background-color: white;
	display: flex;
	align-items: center;
	justify-content: space-between;
	.chat-input-box {
		width: 709rpx;
		line-height: 75rpx;
		font-size: 28rpx;
		color: #141418;
		display: flex;
		justify-content: space-between;
		align-items: center;
		align-items: center;
		background: #f5f5f5;
		border-radius: 38rpx;
		padding: 7rpx 7rpx 7rpx 65rpx;
		.uni-input {
			width: 80%;
			padding-right: 20rpx;
		}
		.submitBtn {
			width: 119rpx;
			height: 63rpx;
			background-color: $u-text-color;
			color: white;
			margin: 0;
			border-radius: 32rpx;
			font-size: 30rpx;
			text-align: center;
			line-height: 63rpx;
		}
	}
}
</style>
